package com.alibaba.sdk.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.sdk.model.entity.User;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;

import java.util.Collection;

/**
 * session相关方法封装
 *
 * @ writer Shawn(Shawn_0217@163.com)
 * @ date & time 2021/4/26 22:59
 * @ company alibaba
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE) // 表示private范围的构造器
public class SessionUtil {

    /**
     * 获取session中的用户信息
     *
     * @return User 用户信息
     */
    public static User getCurrentUser() {
        return (User) SecurityUtils.getSubject().getPrincipal();
    }

    /**
     * 用户退出登录
     */
    public static void logout() {
        SecurityUtils.getSubject().logout();
    }

    /**
     * 用户session中存放数据
     *
     * @param key    存放数据的key
     * @param object 存放数据对象
     */
    public static void put(String key, Object object) {
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute(key, object);
    }

    /**
     * 获取存储在session中的数据
     *
     * @param key session中数据的key
     * @return Object session中保存的数据
     */
    public static Object get(String key) {
        Session session = SecurityUtils.getSubject().getSession();
        return session.getAttribute(key);
    }

    /**
     * 获取存储在session中的数据, 指定返回结果类型
     *
     * @param key    session中数据的key
     * @param target 返回结果类型
     * @param <T>    返回结果指定泛型
     * @return T session中保存的数据
     */
    public static <T> T get(String key, Class<T> target) {
        Session session = SecurityUtils.getSubject().getSession();
        Object attribute = session.getAttribute(key);

        return JSON.parseObject(JSON.toJSONString(attribute), target);
    }

    /**
     * 踢出用户session
     * 注意: shiro也一般用于小项目，小型项目用户数量少可以使用，大项目会有效率问题
     *
     * @param username 用户名
     */
    public static void kickOutUser(String username) {
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();

        // 获取所有已登录用户的session列表
        Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        String currentUserSessionId = SecurityUtils.getSubject().getSession().getId().toString();

        if (sessions.size() > 1) {
            log.info("仅允许单用户登录,开始清理遗留用户信息~");
            for (Session session : sessions) {
                if (StringUtils.equals(username, user.getUsername()) && !currentUserSessionId.equals(session.getId())) {
                    sessionManager.getSessionDAO().delete(session);
                    log.info("清理用户session: {}[SessionId: {}]", username, currentUserSessionId);
                    return;
                }
            }
        } else {
            log.info("无可清理用户信息~");
        }
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    public static User getUserInfo() {
        Object user = SecurityUtils.getSubject().getPrincipal();
        if (user != null) {
            return (User) user;
        }
        return null;
    }
}